using UnityEngine;
using System;
using System.Collections;


public class Robot : MonoBehaviour {
	
	Job currentJob;
	bool hasAJob;
	double pressureInTank;
	bool addedStatustoList;
	bool atJobSite;
	double x, y, z;
	int jobX, jobY, jobZ;
	
	private ArrayList path;
	private int pathIndex;
	Point nextPoint;
	
	double rateOfMovement;
	
	public bool hasMiningTool, hasConstructionTool, hasDeconstructionTool;
	public double rateOfConstruction, rateOfDeconstruction, rateOfMining;
	public ArrayList tools, miningTools, constructionTools, deconstructionTools;
	
	public Item hauledItem;
	
	// Use this for initialization
	void Start () {
		hasAJob = false;
		currentJob = null;
		pressureInTank = 10000;
		nextPoint = new Point(0,0,0);
		
		hasMiningTool = false;
		hasConstructionTool = false;
		hasDeconstructionTool = false;
		
		rateOfConstruction = 1;
		rateOfMining = 1;
		rateOfDeconstruction = 1;
		
		tools = new ArrayList();
		miningTools = new ArrayList();
		constructionTools = new ArrayList();
		deconstructionTools = new ArrayList();
	}
	
	// Update is called once per frame
	void Update () {
		
		if (!hasAJob){
			if (pressureInTank < 500){
				addedStatustoList = true;
				//refill with steam
			}
			
			if (!hasConstructionTool | !hasDeconstructionTool | !hasMiningTool){
				if (!hasConstructionTool){
					foreach (Tool t in Controller.getUnusedTools()){
						if ((t.isConstructionTool) & (!addedStatustoList)){
							addedStatustoList = true;
							currentJob = new EquipJob(t, t.x, t.y, t.z);
						}
					}
				} if (!hasDeconstructionTool){
					foreach (Tool t in Controller.getUnusedTools()){
						if ((t.isDeconstructionTool) & (!addedStatustoList)){
							addedStatustoList = true;
							currentJob = new EquipJob(t, t.x, t.y, t.z);
						}
					}
				} if (!hasMiningTool){
					foreach (Tool t in Controller.getUnusedTools()){
						if ((t.isMiningTool) & (!addedStatustoList)){
							addedStatustoList = true;
							assignJob(new EquipJob(t, t.x, t.y, t.z));
						}
					}
				}
			}
			
			if (!addedStatustoList){
				addedStatustoList = true;
				Controller.addRobot(this);
				print ("Data transmitted");
			}
		} if (atJobSite & hasAJob){
			bool done = false;
			if (currentJob.jobType == 1){
				done = ((BuildingOperationJob)(currentJob)).workOn(1, this);
			} else if (currentJob.jobType == 2){
				done = ((ConstructionJob)(currentJob)).workOn(1, this);
			} else if (currentJob.jobType == 3){
				done = ((DeconstructionJob)(currentJob)).workOn(1, this);
			} else if (currentJob.jobType == 4) {
				done = ((EquipJob)(currentJob)).workOn(this);
				done = true;
			} else if (currentJob.jobType == 5){
				done = ((HaulingJob)(currentJob)).workOn(1, this);
			} else if (currentJob.jobType == 6){
				done = ((MiningJob)(currentJob)).workOn(1, this);
			} else {
				print ("Snork");
			}
			//print (currentJob.percentageComplete);
			if (done){
				Controller.finishedJob(this, currentJob);
				currentJob = null;
				hasAJob = false;
				addedStatustoList = false;
				Debug.Log("Done with Job");
			}
		}
		if (hasAJob & !atJobSite){
			rateOfMovement = 0;
			foreach (Tool t in tools){
				rateOfMovement += (float)(t.material.weightModifier);
			}
			
			rateOfMovement = (0.05 / (rateOfMovement + 1));
			//Debug.Log(rateOfMovement);
						
			nextPoint = (Point)(path[pathIndex]);
			bool goodToMoveOn = true;
			pathTo(nextPoint.x, nextPoint.y, nextPoint.z, rateOfMovement);
			if((int)(x) != nextPoint.x){
				goodToMoveOn = false;
				//Debug.Log (x);
			} else if((int)(y) != nextPoint.y){
				goodToMoveOn = false;
				//Debug.Log(y);
			} else if((int)(z)!= nextPoint.z){
				goodToMoveOn = false;
				//Debug.Log(z);
			}
			
			if (goodToMoveOn){
				pathIndex += 1;
			}
			if (((int)x == jobX) & ((int)y == jobY) & ((int)z == jobZ)){
				x = (int) x;
				y = (int) y;
				z = (int) z;
				atJobSite = true;
				pathIndex = 0;
			}
			
		}
		
	}
	
	public void addConstructionTool(ConstructionTool tool){
		hasConstructionTool = true;
		rateOfConstruction = tool.speedWithTool;
		tools.Add (tool);
		constructionTools.Add (tool);
	}
	
	public void addDeconstructionTool(DeconstructionTool tool){
		hasDeconstructionTool = true;
		rateOfDeconstruction = tool.speedWithTool;
		tools.Add(tool);
		deconstructionTools.Add (tool);
	}
	
	public void addMiningTool(MiningTool tool){
		hasMiningTool = true;
		rateOfMining = tool.speedWithTool;
		tools.Add (tool);
		miningTools.Add (tool);
	}
	
	public void assignJob(Job j){
		print ("Job Assigned");
		currentJob = j;
		hasAJob = true;
		atJobSite = false;
		jobX = j.x;
		jobY = j.y;
		jobZ = j.z;
		z = jobZ;
		path = generatePath(new Point((int)(x), (int)(y), (int)(z)), new Point((int)(jobX), (int)(jobY), (int)(jobZ)));
	}
	
	ArrayList generatePath(Point startLoc, Point goalLoc){
		ArrayList open = new ArrayList();
		ArrayList attemptingPath = new ArrayList();
		ArrayList triedPoints = new ArrayList();
		
		open.Add(startLoc);
		attemptingPath.Add(startLoc);
		
		Point pointToTry = startLoc;
		Point bestSoFar = startLoc;
		
		while (!pointToTry.isEqualTo(goalLoc)){
			
			// Generates points next to current one
			Point[] adjacentpoints = pointToTry.getAdjacentPoints();
			// Finds one with lowest cost, and goes from there
			for (int i = 0; i < 7; i++){
				if (adjacentpoints[i].getFCost(goalLoc) < bestSoFar.getFCost(goalLoc) + 1){
					if ((!adjacentpoints[i].occupied)&(!triedPoints.Contains(adjacentpoints[i]))){
						bestSoFar = adjacentpoints[i];
					}
				}
			}
			
			if (pointToTry.isEqualTo(startLoc)){
				attemptingPath = null;
				attemptingPath = new ArrayList();
			} else {
				triedPoints.Add(bestSoFar);
			}
			
			pointToTry = bestSoFar;
			attemptingPath.Add(pointToTry);
			
		}
		return attemptingPath;
		
		
	}
	
	void pathTo(int pathX, int pathY, int pathZ, double travelSpeed){
		if (!(x == pathX & y == pathY & z == pathZ)) {
			if (x < pathX){
				x +=  travelSpeed;	
			} else if (x > pathX){
				x -= travelSpeed;
			}
			if (y < pathY){
				y += travelSpeed;	
			} else if (y > pathY){
				y -= travelSpeed;
			}
			if (z < pathZ){
				z += travelSpeed;	
			} else if (z > pathZ){
				z -= travelSpeed;
			}
				
		}
		transform.position = new Vector3((float)x, (float)y, (float)z);
		
	}
	
	public Point getPostion(){
		Point p = new Point((int)(x), (int)(y), (int)(z));
		return p;
	}
	
	
}
